#include "mpp_display_buffer.h"
#include "mpp_display_util.h"




uint32_t mpp_display_buffer::mpp_buffer_get_id()
{
    return this->fb_id;
}
void* mpp_display_buffer::mpp_buffer_get_addr()
{
    return this->map_addr;
}
//
int mpp_display_buffer::mpp_add_fb_sp_bo()
{
    int ret = 0; 
    mpp_disp_util::depict_shape shape = {0};
    //mpp_disp_util::depict_men    mem= {0};

    mpp_disp_util::mpp_format_depict_sharp(this->format,this->width,this->height,this->handle,
                                 this->pitch,&shape);        //--用格式，宽度，高度，还有句柄等值，拿到内存的描述结构体


    ret = drmModeAddFB2(this->fd, this->width, this->height,
                        this->format,  
                        shape.handles, shape.pitches, shape.offsets,    // --把内存的描述赋值给drm
                        &this->fb_id, // --拿到  fb_id
                        this->flags);     
    if (ret) {
        printf("failed to create fb ret=%d\n", ret);
        return ret;
    }
    return 0;

   //mpp_disp_util::mpp_format_depict_sharp(this->format,&mem);                              

}
int mpp_display_buffer::mpp_map_sp_bo()
{
    int ret;
    struct drm_mode_map_dumb md;

    if (this->map_addr)
        return 0;

    if(this->handle){
        md.handle = this->handle;
        ret = drmIoctl(this->fd, DRM_IOCTL_MODE_MAP_DUMB, &md);
        if (ret) {
            printf("failed to map sp_bo ret=%d\n", ret);
            return ret;
        }

        this->map_addr = mmap(NULL, this->size, PROT_READ | PROT_WRITE, MAP_SHARED,
                        this->fd, md.offset);
        if (this->map_addr == MAP_FAILED) {
            printf("failed to map bo ret=%d\n", -errno);
            return -errno;
        }
    }
    
    return 0;
}

void mpp_display_buffer::mpp_free_sp_bo()
{
    int ret;
    struct drm_mode_destroy_dumb dd;



    if (this->map_addr){
        munmap(this->map_addr, this->size);
        this->map_addr = NULL;
    }
        

    if (this->fb_id) {
        ret = drmModeRmFB(this->fd, this->fb_id);
        if (ret)
            printf("Failed to rmfb ret=%d!\n", ret);
        this->fb_id = 0;
    }

    if (this->handle) {
        dd.handle = this->handle;
        ret = drmIoctl(this->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dd);
        if (ret)
            printf("Failed to destroy buffer ret=%d\n", ret);
        this->handle = 0;
    }

}

/*目前支持持DRM_FORMAT_ARGB8888 DRM_FORMAT_XRGB8888 DRM_FORMAT_RGBA8888 格式的填充*/
void mpp_display_buffer::mpp_fill_bo(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
    mpp_draw_rect( 0, 0, this->width, this->height, a, r, g, b);
}
void mpp_display_buffer::mpp_draw_rect(uint32_t x, uint32_t y, uint32_t width,
                                            uint32_t height, uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
    uint32_t i, j, xmax = x + width, ymax = y + height;

    if (xmax > this->width)
        xmax = this->width;
    if (ymax > this->height)
        ymax = this->height;

    for (i = y; i < ymax; i++) {
        uint8_t* row = (uint8_t*)this->map_addr + i * this->pitch;

        for (j = x; j < xmax; j++) {
            uint8_t* pixel = row + j * 4;

            if (this->format == DRM_FORMAT_ARGB8888 || this->format == DRM_FORMAT_XRGB8888) {
                pixel[0] = b;
                pixel[1] = g;
                pixel[2] = r;
                pixel[3] = a;
            } else if (this->format == DRM_FORMAT_RGBA8888) {
                pixel[0] = r;
                pixel[1] = g;
                pixel[2] = b;
                pixel[3] = a;
            }
        }
    }
}
bool mpp_display_buffer::mpp_is_exist()
{
    if(this->handle && this->map_addr && this->fb_id)
        return true;
    return false;
}
/**
 * @brief Construct a new mpp display buffer::mpp display buffer object 创建BUFFER
 * 
 * @param fd 
 * @param width 
 * @param height 
 * @param format 
 * @param flags 
 */
mpp_display_buffer::mpp_display_buffer(int fd, uint32_t width, uint32_t height,
                                                                                                uint32_t format, uint32_t flags)
{
    int ret = 0;
    struct drm_mode_create_dumb arg={0};
    memset(&arg, 0, sizeof(arg));

    arg.height = height;
    arg.width = width;
    this->bpp = mpp_disp_util::mpp_format_to_bpp(format);
    arg.bpp = this->bpp;
    arg.flags = 0;
    if(fd<=0)
        return ;
    ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &arg);
    if (ret) {
        printf("failed to create DRM_IOCTL_MODE_CREATE_DUMB %d\n", ret);
        goto err;
    }
    this->fd = fd;
    this->width = width;
    this->height = height;
    this->depth = depth ;
    this->bpp = bpp;
    this->format = format;
    this->flags = 0;

    this->handle = arg.handle;
    this->pitch = arg.pitch;
    this->size = arg.size;

    ret =mpp_add_fb_sp_bo();
    if(ret) 
        goto err;

    ret =mpp_map_sp_bo();
    if(ret) 
        goto err;


    return ;
    err:
        mpp_free_sp_bo();
        return ;
}
mpp_display_buffer::~mpp_display_buffer()
{
    mpp_free_sp_bo();
}